package com.college.common.utils.security;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.security.MessageDigest;




public class PBECryptUtils {

	private static final Logger LOG = LoggerFactory.getLogger(PBECryptUtils.class);

	private static final PBECryptUtils SINGLETON = new PBECryptUtils();


	private static final String ALGORITHM = "PBEWithMD5AndDES";



	private static final int ITERATION_COUNT = 100;



	private static final String CHARSET = "UTF-8";



//	public static final String DBCRYPT_PBE_PWD = "DBCRYPT_PBE_PWD";
	public static final String DBCRYPT_PBE_PWD =  "NOrSNY7MGNA57LZH";


	private static Key PBE_KEY;

	public PBECryptUtils() {
		super();
		initCryptAlgorithm();
	}



	public void initCryptAlgorithm() {
		// 从环境变量获取
		String dbCryptPbePwd = "NOrSNY7MGNA57LZH";
		if (StringUtils.isBlank(dbCryptPbePwd)) {
			LOG.error("Can't read secret-key for PBE from system environment.");
			throw new RuntimeException("Can't read secret-key for PBE from system environment.");
		}
		// 密钥彩礼转换
		PBEKeySpec keySpec = new PBEKeySpec(dbCryptPbePwd.toCharArray());
		try {
			// 实例化
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
			// 生成密钥
			PBE_KEY = keyFactory.generateSecret(keySpec);
		} catch (Exception e) {
			throw new RuntimeException("Init crypt algorithm Exception.", e);
		}

	}

	public static PBECryptUtils getInstance() {
		return SINGLETON;
	}




	public String encrypt(String in) {
		try {
			// 数据byte[]
			byte[] input = in.getBytes(CHARSET);

			// 计算盐
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.update(input);
			in = DatatypeConverter.printHexBinary(md5.digest(input)).toLowerCase();
			StringBuilder sb = new StringBuilder(128);
			for (int i = 0; i < in.length(); i += 4) {
				sb.append(in.charAt(i));
			}
			byte[] salt = sb.toString().getBytes(CHARSET);

			// 加密数据
			PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE, PBE_KEY, paramSpec);
			byte[] data = cipher.doFinal(input);

			sb.append(Base64.encodeBase64String(data));
			// 加密后的字符串去掉制表符、换行符
			return sb.toString().trim();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}



	public String decrypt(String value) {
		if (StringUtils.isEmpty(value)) {
			return null;
		}

		if (StringUtils.length(value) < 8) {
			return value;
		}

		try {
			// 先解密得到盐
			String saltEncrypt = StringUtils.substring(value, 0, 8);
			byte[] salt = saltEncrypt.getBytes(CHARSET);

			// base解密
			String dataEncrypt = StringUtils.substring(value, 8);
			byte[] data = Base64.decodeBase64(dataEncrypt);
			if (null == data || data.length == 0) {
				return value;
			}

			// PEB解密
			PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			cipher.init(Cipher.DECRYPT_MODE, PBE_KEY, paramSpec);
			data = cipher.doFinal(data);

			return new String(data, CHARSET);
		} catch (Exception e) {
			return value;
		}
	}

	public static void main(String[] args) {
		PBECryptUtils pbeCryptUtils = new PBECryptUtils();
		pbeCryptUtils.initCryptAlgorithm();
		System.out.println(pbeCryptUtils.decrypt("9343d3df6N3mbrXbPk0KrVtipA2jNw=="));
	}

}
